#include "game.h"

static uint8_t full_map[HEIGHT_AREA*2][WIDTH_AREA*2] = {0};
static char player_state[4] = {UP_ST, RIGHT_ST, DOWN_ST, LEFT_ST};
static uint32_t num_food = 0;

uint8_t q_map[HEIGHT_AREA][WIDTH_AREA] = {0};

extern node_t *players; 

void expand_map()
{
    uint8_t mark;
    for (int y = 0; y < HEIGHT_AREA; ++y)
    {
        for (int x = 0; x < WIDTH_AREA; ++x)
        {
            if (q_map[y][x] == PLAYER)
                mark = FOOD;
            else
                mark = q_map[y][x];
                // mark = FOOD;

            full_map[y][x] = mark;
            full_map[HEIGHT_AREA*2 - 1 - y][WIDTH_AREA*2 - 1 - x] = mark;
            full_map[HEIGHT_AREA*2 - 1 - y][x] = mark;
            full_map[y][WIDTH_AREA*2 - 1 - x] = mark;
        }
    }
}


void print_map(int x_start, int y_start)
{
    for (int y = 0; y < HEIGHT_AREA*2; ++y)
    {
        for (int x = 0; x < WIDTH_AREA*2; ++x)
        {
            if (full_map[y][x] == FOOD)
                mvaddch(y+y_start, x+x_start, FOOD_CH);
            else if (full_map[y][x] == WALL)
                mvaddch(y+y_start, x+x_start, WALL_CH);
            else if (full_map[y][x] == PLAYER)
                mvaddch(y+y_start, x+x_start, FOOD_CH);
            else
                mvaddch(y, x, '!');
        }
    }
}


void print_border(int x_start, int y_start)
{
    for (int y = 0; y < HEIGHT_AREA*2+1; ++y)
    {
        mvaddch(y + y_start, x_start, WALL_CH);
        mvaddch(y + y_start, x_start+WIDTH_AREA*2+1, WALL_CH);
    }

    for (int x = 0; x < WIDTH_AREA*2+2; ++x)
    {
        mvaddch(y_start, x + x_start, WALL_CH);
        mvaddch(y_start + HEIGHT_AREA*2+1, x + x_start, WALL_CH);
    }
}


void print_players(ex_player_t *cur_player)
{
    node_t *iter;
    ex_player_t *pl;

    iter = players->next;
    while (iter != NULL)
    {
        pl = (ex_player_t *)iter->data;

        if (pl->pl.start_y == cur_player->pl.start_y && pl->pl.start_x == cur_player->pl.start_x)
        {
            attron(COLOR_PAIR(PLAYER_PAIR));
            mvaddch(pl->pl.start_y + START_MAP_Y, pl->pl.start_x + START_MAP_X, 
                    player_state[pl->pl.start_direction]);
            attroff(COLOR_PAIR(PLAYER_PAIR));
        }
        else
        {
            attron(COLOR_PAIR(ENEMY_PAIR));
            mvaddch(pl->pl.start_y + START_MAP_Y, pl->pl.start_x + START_MAP_X, 
                    player_state[pl->pl.start_direction]);
            attroff(COLOR_PAIR(ENEMY_PAIR));
        }

        iter = iter->next;
    }
}


void draw_map()
{
    print_map(START_MAP_X, START_MAP_Y); 
    print_border(START_BORDER_X, START_BORDER_Y);
    // print_players();

    refresh();
}


void move_players(char *name, uint8_t dir)
{
    node_t *iter;
    ex_player_t *pl;

    uint32_t x, y;

    iter = players->next;
    while (iter != NULL)
    {
        pl = (ex_player_t *)iter->data;

        if (strcmp(pl->pl.player_name, name) == 0 && 
                (dir == RIGHT || dir == DOWN || dir == LEFT || dir == UP))
            pl->pl.start_direction = dir;


        if (pl->pl.start_direction == DOWN)
        {
            y = pl->pl.start_y + 1;
            x = pl->pl.start_x;

            if (y < HEIGHT_AREA*2)
            {
                if (full_map[y][x] == WALL || check_collision_players(pl->pl.player_name, y, x))
                    goto NEXT_ITER;
                        
                mvaddch(START_MAP_Y + pl->pl.start_y, 
                        START_MAP_X + pl->pl.start_x, SPACE_CH);

                pl->pl.start_y += 1;
            } 
        }
        else if (pl->pl.start_direction == RIGHT)
        {
            y = pl->pl.start_y;
            x = pl->pl.start_x + 1;

            if (x < WIDTH_AREA*2)
            {
                if (full_map[y][x] == WALL || check_collision_players(pl->pl.player_name, y, x))
                    goto NEXT_ITER;
                
                mvaddch(START_MAP_Y + pl->pl.start_y, 
                        START_MAP_X + pl->pl.start_x, SPACE_CH);

                pl->pl.start_x += 1;
            }
        }
        else if (pl->pl.start_direction == UP)
        {
            y = pl->pl.start_y - 1;
            x = pl->pl.start_x;

            if ((int32_t)y >= 0)
            {
                if (full_map[y][x] == WALL || check_collision_players(pl->pl.player_name, y, x))
                    goto NEXT_ITER;
                
                mvaddch(START_MAP_Y + pl->pl.start_y, 
                        START_MAP_X + pl->pl.start_x, SPACE_CH);

                pl->pl.start_y -= 1;
            }
        }
        else if (pl->pl.start_direction == LEFT)
        {
            y = pl->pl.start_y;
            x = pl->pl.start_x - 1;

            if ((int32_t)x >= 0)
            {
                if (full_map[y][x] == WALL || check_collision_players(pl->pl.player_name, y, x))
                    goto NEXT_ITER;
                
                mvaddch(START_MAP_Y + pl->pl.start_y, 
                        START_MAP_X + pl->pl.start_x, SPACE_CH);

                pl->pl.start_x -= 1;
            }
        }

        if (full_map[pl->pl.start_y][pl->pl.start_x] == FOOD)
        {
            full_map[pl->pl.start_y][pl->pl.start_x] = SPACE;
            pl->score += 1;
            num_food -= 1;
        }

    NEXT_ITER:
        iter = iter->next;
    }
}


void print_score(int y, int x, ex_player_t *player)
{
    char scr[MAX_NAME_LEN + 30];
    itoa(scr, player->score);

    mvaddstr(y, START_BORDER_X + WIDTH_AREA*2 + x, scr);
}


void reverse_str(char *str, size_t len)
{
    char tmp;
    for (int i = 0; i < len/2; ++i)
    {
        tmp = str[i];
        str[i] = str[len - i - 1];
        str[len - i - 1] = tmp;
    }
}


void itoa(char *buf, int num)
{
    uint8_t i = 0;

    while (num > 0)
    {
        buf[i] = num % 10 + '0';
        num /= 10;
        i++;
    }

    reverse_str(buf, i);
    buf[i] = '\0';
}


void counting_food(uint32_t num_players)
{
    for (int y = 0; y < HEIGHT_AREA*2; ++y)
    {
        for (int x = 0; x < WIDTH_AREA*2; ++x)
        {
            if (full_map[y][x] == FOOD)
                num_food += 1;
        }
    }

    num_food -= num_players;
}


int check_end_game()
{
    if (num_food == 0)
        return 1;

    return 0;
}


void end_game()
{
    node_t *iter;
    ex_player_t *max;

    ex_player_t *pl;

    char winner_mes[1024];

    iter = players->next;
    max = iter->data;
    while (iter != NULL)
    {
        pl = (ex_player_t *)iter->data;
        if (pl->score > max->score)
            max = pl;
        
        iter = iter->next;
    }

    clear();
    refresh();

    sprintf(winner_mes, "'%s' is winner ! Score: %d\n", max->pl.player_name, max->score);
    mvaddstr(0, 0, winner_mes);
    endwin();
}


int check_collision_players(char *name_player, uint32_t new_y, uint32_t new_x)
{
    node_t *iter;
    ex_player_t *pl;

    iter = players->next;
    while(iter != NULL) 
    {
        pl = (ex_player_t *)iter->data;
        if (strcmp(name_player, pl->pl.player_name) == 0)
            goto NEXT_ITER;

        if (pl->pl.start_y == new_y && pl->pl.start_x == new_x)
            return 1;

    NEXT_ITER:
        iter = iter->next;
    }

    return 0;
}
